
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>直播播放器</title>
<style>
body, html { padding: 0; margin: 0; background: #000; font-family: Arial, sans-serif; }
.container { position: relative; max-width: 800px; margin: 0 auto; background: #000; }
#video1 { width: 100%; height: 300px; background-color: #000; display: block; }

/* 控制栏样式 */
.control-bar { position: absolute; bottom: 0; left: 0; right: 0; background: linear-gradient(transparent, rgba(0,0,0,0.7)); padding: 15px 10px 10px; color: #fff; display: flex; justify-content: space-between; align-items: center; z-index: 100; transition: opacity 0.3s; }
.control-bar.hidden { opacity: 0; pointer-events: none; }
.control-left { display: flex; align-items: center; }
.play-btn, .mute-btn { background: none; border: none; color: #fff; font-size: 20px; cursor: pointer; margin-right: 15px; }
.control-center { flex-grow: 1; text-align: center; font-size: 13px; }
.live-indicator { display: inline-block; background: #e00; padding: 2px 8px; border-radius: 4px; margin-right: 8px; }
.control-right { display: flex; align-items: center; }
.fullscreen-btn { background: none; border: none; color: #fff; font-size: 18px; cursor: pointer; }

/* 消息覆盖层 */
.message-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; flex-direction: column; justify-content: center; align-items: center; background: rgba(0,0,0,0.7); z-index: 200; color: #fff; padding: 20px; text-align: center; }
.message-title { font-size: 18px; margin-bottom: 15px; color: #ffd700; }
.message-content { font-size: 15px; line-height: 1.5; max-width: 400px; }
.countdown { color: #ff6b6b; font-weight: bold; margin-top: 10px; }
.reload-btn { margin-top: 20px; padding: 8px 20px; background: #e00; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; }

/* 状态指示器 */
.status-indicator { position: absolute; top: 10px; right: 10px; background: rgba(0,0,0,0.6); color: #fff; padding: 5px 10px; border-radius: 4px; font-size: 12px; z-index: 150; }

/* 性能面板 */
.stats-panel { position: absolute; top: 50px; right: 10px; background: rgba(0,0,0,0.6); color: #fff; padding: 10px; border-radius: 4px; font-size: 12px; z-index: 150; max-width: 200px; }
.stats-row { display: flex; justify-content: space-between; margin-bottom: 5px; }
.stats-label { color: #ccc; }
.stats-value { font-weight: bold; }
.stats-value.good { color: #4caf50; }
.statsValue.average { color: #ff9800; }
.stats-value.poor { color: #f44336; }

/* 加载动画 */
.loader { width: 40px; height: 40px; margin: 20px auto; border: 4px solid #333; border-radius: 50%; border-top: 4px solid #e00; animation: spin 1s linear infinite; }
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }

/* 手动播放覆盖（默认隐藏，仅在自动播放被阻止时显示） */
.manual-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: none; justify-content: center; align-items: center; background: rgba(0,0,0,0.6); z-index: 250; }
.manual-overlay .btn { padding: 12px 24px; background: #e00; color: #fff; border: none; border-radius: 6px; font-size: 16px; cursor: pointer; }
</style>

<script src="https://sailor-grubby.sage-streak-fei.com:2096/zbkj/flv.min.js"></script>
<script src="https://sailor-grubby.sage-streak-fei.com:2096/zbkj/hls.js"></script>
</head>
<body>
<div class="container" id="container">
  <!-- 保留 playsinline，设置 muted 提高静音 autoplay 成功率；不加 autoplay -->
  <video id="video1" playsinline webkit-playsinline muted controls></video>

  <!-- 控制栏 -->
  <div class="control-bar" id="control-bar">
    <div class="control-left">
      <button class="play-btn" id="play-btn">▶</button>
      <button class="mute-btn" id="mute-btn">🔇</button>
    </div>
    <div class="control-center">
      <span class="live-indicator">直播中</span>
      <span id="time-display">21:33:25</span>
    </div>
    <div class="control-right">
      <button class="fullscreen-btn" id="fullscreen-btn">⛶</button>
    </div>
  </div>

  <!-- 消息覆盖层 -->
  <div class="message-overlay" id="message-overlay">
    <div class="message-title" id="message-title">直播提示</div>
    <div class="message-content" id="message-content">
      搅珠直播时间为每晚 <b style="color:#ff6b6b">21:33</b>（北京时间），敬请查看
    </div>
    <div class="countdown" id="countdown"></div>
    <button class="reload-btn" id="reload-btn">刷新页面</button>
  </div>

  <!-- 手动播放覆盖（默认隐藏，仅在自动播放被浏览器阻止时显示） -->
  <div class="manual-overlay" id="manual-overlay" style="display:none;">
    <button class="btn" id="manual-play-btn">点击开始播放</button>
  </div>

  <div class="status-indicator" id="status-indicator" style="display:none;">等待初始化</div>

  <div class="stats-panel" id="stats-panel" style="display:none;">
    <div class="stats-row"><span class="stats-label">状态:</span><span class="stats-value" id="stats-status">等待</span></div>
    <div class="stats-row"><span class="stats-label">协议:</span><span class="stats-value" id="stats-protocol">-</span></div>
    <div class="stats-row"><span class="stats-label">缓存:</span><span class="stats-value" id="stats-buffer">0.0s</span></div>
    <div class="stats-row"><span class="stats-label">延迟:</span><span class="stats-value" id="stats-latency">-</span></div>
    <div class="stats-row"><span class="stats-label">重连:</span><span class="stats-value" id="stats-reconnects">0</span></div>
  </div>

  <div class="loader" id="loader" style="display:none;"></div>
</div>

<script>
// 配置
const CONFIG = {
  liveTime: { start: { hour: 21, minute: 33 }, end: { hour: 21, minute: 35 } },
  sources: {
    flv: "https://play3636.zdwafis.com/live/mosixmark.flv",
    hls: "https://play3636.zdwafis.com/live/mosixmark.m3u8",
    backupFlv: "https://play3636.zdwafis.com/live/mosixmark.flv",
    backupHls: "https://play3636.zdwafis.com/live/mosixmark.m3u8"
  },
  buffers: { max: 10, min: 3 },
  timeouts: { connection: 10000, retry: 3000, stats: 2000 },
  retries: { max: 5 }
};

// 全局
let player = null;
let playerType = null;
let isLiveTime = false;
let retryCount = 0;
let liveStartTime = null;
let liveEndTime = null;
let isPlaying = false;
let isMuted = true;
let statsInterval = null;
let liveTimeCheckInterval = null;

// DOM 元素
const elements = {
  video: null,
  messageOverlay: null,
  messageTitle: null,
  messageContent: null,
  countdown: null,
  reloadBtn: null,
  statusIndicator: null,
  statsPanel: null,
  statsStatus: null,
  statsProtocol: null,
  statsBuffer: null,
  statsLatency: null,
  statsReconnects: null,
  controlBar: null,
  playBtn: null,
  muteBtn: null,
  fullscreenBtn: null,
  loader: null,
  manualOverlay: null,
  manualPlayBtn: null
};

// 是否 iOS WebKit（用于决定是否在静音时尝试自动播放）
function isIosWebkit() {
  const ua = navigator.userAgent || '';
  const isIOS = /iP(hone|od|ad)/.test(ua);
  const isWebKit = /AppleWebKit/.test(ua) && !/CriOS|OPiOS|FxiOS|UCBrowser/.test(ua);
  return isIOS && isWebKit;
}

// 初始化
function init() {
  elements.video = document.getElementById('video1');
  elements.messageOverlay = document.getElementById('message-overlay');
  elements.messageTitle = document.getElementById('message-title');
  elements.messageContent = document.getElementById('message-content');
  elements.countdown = document.getElementById('countdown');
  elements.reloadBtn = document.getElementById('reload-btn');
  elements.statusIndicator = document.getElementById('status-indicator');
  elements.statsPanel = document.getElementById('stats-panel');
  elements.statsStatus = document.getElementById('stats-status');
  elements.statsProtocol = document.getElementById('stats-protocol');
  elements.statsBuffer = document.getElementById('stats-buffer');
  elements.statsLatency = document.getElementById('stats-latency');
  elements.statsReconnects = document.getElementById('stats-reconnects');
  elements.controlBar = document.getElementById('control-bar');
  elements.playBtn = document.getElementById('play-btn');
  elements.muteBtn = document.getElementById('mute-btn');
  elements.fullscreenBtn = document.getElementById('fullscreen-btn');
  elements.loader = document.getElementById('loader');
  elements.manualOverlay = document.getElementById('manual-overlay');
  elements.manualPlayBtn = document.getElementById('manual-play-btn');

  setupEventListeners();
  calculateLiveTime();
  initVideoElement();
  checkLiveTime();
  liveTimeCheckInterval = setInterval(checkLiveTime, 1000);
  setupControlBarAutoHide();
  updateStatus('播放器初始化完成');
}

// 事件绑定
function setupEventListeners() {
  elements.reloadBtn.addEventListener('click', () => location.reload());
  elements.playBtn.addEventListener('click', togglePlayback);
  elements.muteBtn.addEventListener('click', toggleMute);
  elements.fullscreenBtn.addEventListener('click', toggleFullscreen);

  elements.video.addEventListener('click', () => { if (isPlaying) pausePlayback(); else startPlayback(); });
  elements.video.addEventListener('dblclick', toggleFullscreen);

  elements.video.addEventListener('play', () => { isPlaying = true; elements.playBtn.textContent = '⏸'; updateStatus('播放中'); });
  elements.video.addEventListener('pause', () => { isPlaying = false; elements.playBtn.textContent = '▶'; updateStatus('已暂停'); });
  elements.video.addEventListener('waiting', () => { elements.loader.style.display = 'block'; updateStatus('缓冲中...'); });
  elements.video.addEventListener('playing', () => { elements.loader.style.display = 'none'; updateStatus('播放中'); });
  elements.video.addEventListener('ended', () => updateStatus('播放结束'));
  elements.video.addEventListener('error', () => handleError('视频播放错误'));

  document.addEventListener('fullscreenchange', handleFullscreenChange);
  document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
  document.addEventListener('mozfullscreenchange', handleFullscreenChange);
  document.addEventListener('MSFullscreenChange', handleFullscreenChange);

  // 手动播放按钮：默认隐藏，只在 play() 被拒绝时显示
  elements.manualPlayBtn.addEventListener('click', function manualClickHandler() {
    elements.manualOverlay.style.display = 'none';
    try { if (playerType === 'hls' && player && player.startLoad) player.startLoad(); } catch(e){ console.warn(e); }
    elements.video.muted = false;
    elements.video.play().catch(err => handleError('手动播放失败：' + (err && err.message)));
  });
}

// 初始化 video 属性（不加 autoplay）
function initVideoElement() {
  elements.video.muted = true;
  elements.video.setAttribute('playsinline', '');
  elements.video.setAttribute('webkit-playsinline', '');
}

// 计算今天直播时间
function calculateLiveTime() {
  const now = new Date();
  const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate(), CONFIG.liveTime.start.hour, CONFIG.liveTime.start.minute, 0, 0);
  const todayEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate(), CONFIG.liveTime.end.hour, CONFIG.liveTime.end.minute, 0, 0);
  if (todayEnd <= todayStart) todayEnd.setDate(todayEnd.getDate() + 1);
  liveStartTime = todayStart; liveEndTime = todayEnd;
}

// 检查是否在直播时间
function checkLiveTime() {
  const now = new Date();
  const timeDisplay = now.toTimeString().substr(0,8);
  document.getElementById('time-display').textContent = timeDisplay;
  if (now >= liveStartTime && now <= liveEndTime) {
    if (!isLiveTime) { isLiveTime = true; startPlayback(); }
  } else {
    if (isLiveTime) { isLiveTime = false; stopPlayback(); }
    showCountdown(now);
  }
}

function showCountdown(now) {
  let timeDiff, message;
  if (now < liveStartTime) { timeDiff = liveStartTime - now; message = "距离直播开始还有"; }
  else { const nextStart = new Date(liveStartTime); nextStart.setDate(nextStart.getDate() + 1); timeDiff = nextStart - now; message = "距离下次直播还有"; }
  const hours = Math.floor(timeDiff / (1000*60*60));
  const minutes = Math.floor((timeDiff % (1000*60*60)) / (1000*60));
  const seconds = Math.floor((timeDiff % (1000*60)) / 1000);
  elements.countdown.textContent = `${message} ${hours.toString().padStart(2,'0')}:${minutes.toString().padStart(2,'0')}:${seconds.toString().padStart(2,'0')}`;
  elements.messageOverlay.style.display = 'flex';
}

// 启动播放（到点触发）
function startPlayback() {
  if (!isLiveTime) { updateStatus('不在直播时间内'); return; }
  if (player) {
    elements.video.play().catch(function(error) {
      console.warn('直接 play 被阻止', error);
      showManualPlayOverlay();
      handleError('播放失败: ' + (error && error.message));
    });
    return;
  }

  elements.messageOverlay.style.display = 'none';
  elements.loader.style.display = 'block';

  selectPlayerType();
  initPlayer();
}

// 选择播放器类型（保留原优先顺序并支持原生 HLS）
function selectPlayerType() {
  const ua = navigator.userAgent || '';
  const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);

  if (!isMobile && window.flvjs && flvjs.isSupported && flvjs.isSupported()) {
    playerType = 'flv';
  } else if (window.Hls && Hls.isSupported && Hls.isSupported()) {
    playerType = 'hls';
  } else if (elements.video && elements.video.canPlayType && elements.video.canPlayType('application/vnd.apple.mpegurl')) {
    playerType = 'nativeHls';
  } else if (window.flvjs && flvjs.isSupported && flvjs.isSupported()) {
    playerType = 'flv';
  } else {
    handleError('您的浏览器不支持FLV或HLS播放');
    return;
  }

  updateStatus(`使用 ${playerType.toUpperCase()} 播放器`);
  elements.statsProtocol.textContent = playerType.toUpperCase();
}

// 初始化播放器
function initPlayer() {
  if (playerType === 'flv') initFlvPlayer();
  else if (playerType === 'hls') initHlsPlayer();
  else if (playerType === 'nativeHls') {
    // 原生 HLS（iOS）
    try {
      elements.video.src = CONFIG.sources.hls;
      elements.video.load();
      // iOS WebKit 静音时通常允许自动播放
      if (isIosWebkit()) {
        elements.video.play().then(() => {
          updateStatus('原生 HLS 播放开始');
          startStatsMonitoring();
        }).catch(err => {
          console.warn('iOS 自动播放被阻止', err);
          showManualPlayOverlay();
        });
      } else {
        // 非 iOS WebKit 平台不强制自动播放，若被拒绝将在 play() catch 时展示手动按钮
        elements.video.play().catch(err => { console.warn('原生 play 被阻止', err); showManualPlayOverlay(); });
      }
    } catch (e) {
      handleError('原生播放初始化异常：' + e.message);
    }
  }
}

// 初始化 FLV
function initFlvPlayer() {
  destroyPlayer();
  try {
    player = flvjs.createPlayer({
      type: 'flv',
      url: CONFIG.sources.flv,
      isLive: true,
      hasAudio: true,
      hasVideo: true,
      enableStashBuffer: true,
      stashInitialSize: 128,
      enableWorker: true,
      lazyLoad: true,
      lazyLoadMaxDuration: 3 * 60,
      deferLoadAfterSourceOpen: true
    }, {
      reuseRedirectedURL: true,
      seekType: 'range',
      maxBufferLength: CONFIG.buffers.max,
      bufferBehind: CONFIG.buffers.min
    });

    player.on(flvjs.Events.ERROR, function(errorType, errorDetail, errorInfo) {
      handleError(`FLV错误: ${errorType} - ${errorDetail}`);
    });
    player.on(flvjs.Events.STATISTICS_INFO, function(stats) { updateStatsPanel(stats); });

    player.attachMediaElement(elements.video);
    player.load();

    // 直接尝试播放，若被拒绝则显示手动按钮
    elements.video.play().then(function() {
      updateStatus('FLV播放开始');
      startStatsMonitoring();
    }).catch(function(error) {
      console.warn('FLV play 被阻止', error);
      showManualPlayOverlay();
      handleError('FLV播放失败: ' + (error && error.message));
    });
  } catch (e) {
    handleError('FLV 初始化失败：' + e.message);
  }
}

// 初始化 HLS (hls.js) - 保持 autoStartLoad:true（若需更严格控制可改为 false）
function initHlsPlayer() {
  destroyPlayer();
  try {
    player = new Hls({
      debug: false,
      enableWorker: true,
      lowLatencyMode: true,
      autoStartLoad: true,
      maxBufferLength: 90,
      liveSyncDurationCount: 3
    });

    player.on(Hls.Events.ERROR, function(event, data) {
      if (data.fatal) handleError(`HLS错误: ${data.type} - ${data.details}`);
    });

    player.on(Hls.Events.MANIFEST_PARSED, function() {
      elements.video.play().then(function() {
        updateStatus('HLS播放开始');
        startStatsMonitoring();
      }).catch(function(error) {
        console.warn('HLS play 被阻止', error);
        showManualPlayOverlay();
        handleError('HLS播放失败: ' + (error && error.message));
      });
    });

    player.loadSource(CONFIG.sources.hls);
    player.attachMedia(elements.video);
  } catch (e) {
    handleError('HLS 初始化异常：' + e.message);
  }
}

// 显示手动播放覆盖（仅在 play() 被拒绝时调用）
function showManualPlayOverlay() {
  elements.manualOverlay.style.display = 'flex';
  // 按钮事件已在 setupEventListeners 中绑定（一次性）
}

// 启动统计监控
function startStatsMonitoring() {
  if (statsInterval) clearInterval(statsInterval);
  statsInterval = setInterval(updateBufferStats, CONFIG.timeouts.stats);
}

function updateBufferStats() {
  if (!elements.video) return;
  let bufferLength = 0;
  if (elements.video.buffered.length > 0) {
    bufferLength = elements.video.buffered.end(elements.video.buffered.length - 1) - elements.video.currentTime;
  }
  elements.statsBuffer.textContent = bufferLength.toFixed(1) + 's';
  if (bufferLength < 1) {
    elements.statsBuffer.className = 'stats-value poor';
    elements.statsStatus.textContent = '缓冲不足';
    elements.statsStatus.className = 'stats-value poor';
  } else if (bufferLength < 3) {
    elements.statsBuffer.className = 'stats-value average';
    elements.statsStatus.textContent = '缓冲正常';
    elements.statsStatus.className = 'stats-value average';
  } else {
    elements.statsBuffer.className = 'stats-value good';
    elements.statsStatus.textContent = '缓冲良好';
    elements.statsStatus.className = 'stats-value good';
  }
  if (playerType === 'flv' && player) {
    const stats = player.statsInfo;
    if (stats) {
      const latency = stats.downloadLatency ? stats.downloadLatency.toFixed(2) : 'N/A';
      elements.statsLatency.textContent = latency + 's';
    }
  }
}

function updateStatsPanel(stats) {
  if (!stats) return;
  elements.statsReconnects.textContent = retryCount;
  if (stats.downloadLatency !== undefined) elements.statsLatency.textContent = stats.downloadLatency.toFixed(2) + 's';
}

function pausePlayback() {
  if (elements.video) { elements.video.pause(); isPlaying = false; elements.playBtn.textContent = '▶'; updateStatus('已暂停'); }
}
function stopPlayback() { pausePlayback(); destroyPlayer(); retryCount = 0; updateStatus('播放已停止'); }
function togglePlayback() { if (isPlaying) pausePlayback(); else startPlayback(); }
function toggleMute() {
  if (!elements.video) return;
  isMuted = !elements.video.muted;
  elements.video.muted = isMuted;
  elements.muteBtn.textContent = isMuted ? '🔇' : '🔊';
}
function toggleFullscreen() {
  const container = document.getElementById('container');
  if (!document.fullscreenElement && !document.webkitFullscreenElement && !document.mozFullScreenElement && !document.msFullscreenElement) {
    if (container.requestFullscreen) container.requestFullscreen();
    else if (container.webkitRequestFullscreen) container.webkitRequestFullscreen();
    else if (container.mozRequestFullScreen) container.mozRequestFullScreen();
    else if (container.msRequestFullscreen) container.msRequestFullscreen();
  } else {
    if (document.exitFullscreen) document.exitFullscreen();
    else if (document.webkitExitFullscreen) document.webkitExitFullscreen();
    else if (document.mozCancelFullScreen) document.mozCancelFullScreen();
    else if (document.msExitFullscreen) document.msExitFullscreen();
  }
}
function handleFullscreenChange() { /* no-op */ }

function setupControlBarAutoHide() {
  let mouseTimer = null;
  elements.video.addEventListener('mousemove', function() {
    elements.controlBar.classList.remove('hidden');
    if (mouseTimer) clearTimeout(mouseTimer);
    mouseTimer = setTimeout(function() { elements.controlBar.classList.add('hidden'); }, 3000);
  });
}

function handleError(message) {
  console.error(message);
  updateStatus(message);
  elements.messageTitle.textContent = '播放错误';
  elements.messageContent.textContent = message;
  elements.messageOverlay.style.display = 'flex';
  elements.loader.style.display = 'none';

  if (retryCount < CONFIG.retries.max) {
    retryCount++;
    elements.statsReconnects.textContent = retryCount;
    setTimeout(function() {
      updateStatus(`尝试重新连接 (${retryCount}/${CONFIG.retries.max})`);
      destroyPlayer();
      startPlayback();
    }, CONFIG.timeouts.retry);
  } else {
    updateStatus('重试次数超限，请手动刷新');
  }
}

function destroyPlayer() {
  if (player) {
    try {
      if (playerType === 'flv') {
        player.pause && player.pause();
        player.unload && player.unload();
        player.detachMediaElement && player.detachMediaElement();
        player.destroy && player.destroy();
      } else if (playerType === 'hls') {
        player.stopLoad && player.stopLoad();
        player.detachMedia && player.detachMedia();
        player.destroy && player.destroy();
      }
    } catch (e) {}
    player = null;
  }
  if (statsInterval) { clearInterval(statsInterval); statsInterval = null; }
}

function updateStatus(status) {
  elements.statusIndicator.textContent = status;
  elements.statsStatus.textContent = status.length > 10 ? status.substring(0,10) + '...' : status;
}

window.addEventListener('beforeunload', function() {
  destroyPlayer();
  if (liveTimeCheckInterval) clearInterval(liveTimeCheckInterval);
  if (statsInterval) clearInterval(statsInterval);
});

window.addEventListener('load', init);
</script>
</body>
</html>